package com.odata.springboot.starter.odata.odata.processor;

import com.odata.springboot.starter.odata.odata.config.OdataCachedData;
import com.odata.springboot.starter.odata.odata.sql.process.SqlProcessChain;
import com.odata.springboot.starter.odata.odata.sql.sqlBuild.OdataClassMetaData;
import com.odata.springboot.starter.odata.odata.sql.sqlBuild.OdataSqlInfo;
import com.odata.springboot.starter.odata.odata.sql.sqlBuild.OdataSqlInformation;
import com.odata.springboot.starter.odata.odata.sql.sqlBuild.enums.SqlTypeEnum;
import com.odata.springboot.starter.odata.utils.OdataJdbcUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.*;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.List;

/**
 * @author chenYX
 * @date 2021/6/22 14:48
 * @description
 */
@Component
@Slf4j
public class SimpleEntityCollectionProcessor implements EntityCollectionProcessor {


    private OData oData;

    private ServiceMetadata serviceMetadata;

    @Autowired
    private SqlProcessChain sqlProcessChain;


    @Autowired
    private OdataJdbcUtils odataJdbcUtils;


    @Override
    public void readEntityCollection(ODataRequest oDataRequest, ODataResponse oDataResponse, UriInfo uriInfo, ContentType contentType)throws ODataLibraryException {

        //该方法用于"读取"后端的数据（这可以是一个数据库），并将其传递给呼叫 OData 服务的用户
        List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
        UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
        String className = uriResourceEntitySet.getEntityType().getFullQualifiedName().getFullQualifiedNameAsString();


        EntityCollection returnEntityCollection = new EntityCollection();
        try {
            OdataSqlInformation.SqlInformationBuild sqlInformationBuild = new OdataSqlInformation.SqlInformationBuild();
            //获取类的元数据信息
            OdataClassMetaData odataClassMetaData = OdataCachedData.cachedCsdlMetaDataMap.get(className);
            String tableName = odataClassMetaData.getTableName();
            Class aClass = odataClassMetaData.getAClass();
            sqlInformationBuild.buildAClass(aClass);
            sqlInformationBuild.buildTableName(tableName)
                    .buildSqlType(SqlTypeEnum.SELECT);
            sqlProcessChain.process(sqlInformationBuild, uriInfo, aClass, oData);
            OdataSqlInfo odataSqlInfo = sqlInformationBuild.buildSqlInfo();
            List<Entity> entities = odataJdbcUtils.executeSelectSqlAnd2EntityList(odataSqlInfo);
            returnEntityCollection.getEntities().addAll(entities);
            //是否有count
            CountOption countOption = uriInfo.getCountOption();
            if (countOption != null){
                if (countOption.getValue()){
                    OdataSqlInfo countSqlInfo = sqlInformationBuild.buildSelectCountSqlInfo();
                    int count = odataJdbcUtils.executeSelectCount(countSqlInfo);
                    returnEntityCollection.setCount(count);
                }

            }
        } catch (Exception e) {
            log.error("执行sql语句失败{}",e.getMessage(),e);
        }
        EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
        // 3rd: create a serializer based on the requested format (json)
        ODataSerializer serializer = oData.createSerializer(contentType);

        SelectOption selectOption = uriInfo.getSelectOption();
        String selectList = oData.createUriHelper()
                .buildContextURLSelectList(edmEntitySet.getEntityType(), null, selectOption);
        CountOption countOption = uriInfo.getCountOption();
        // 4th: Now serialize the content: transform from the EntitySet object to InputStream
        EdmEntityType edmEntityType = edmEntitySet.getEntityType();
        ContextURL contextUrl = ContextURL.with().selectList(selectList).entitySet(edmEntitySet).build();

        final String id = oDataRequest.getRawBaseUri() + "/" + edmEntitySet.getName();
        EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with().id(id).contextURL(contextUrl).select(selectOption).count(countOption).build();
        SerializerResult serializerResult = serializer.entityCollection(serviceMetadata, edmEntityType, returnEntityCollection, opts);
        InputStream serializedContent = serializerResult.getContent();

        // Finally: configure the response object: set the body, headers and status code
        oDataResponse.setContent(serializedContent);
        oDataResponse.setStatusCode(HttpStatusCode.OK.getStatusCode());
        oDataResponse.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());

    }


    @Override
    public void init(OData oData, ServiceMetadata serviceMetadata) {
        this.oData = oData;
        this.serviceMetadata = serviceMetadata;
    }

}
